#ifndef WORKERGRAPH
#define WORKERGRAPH

/*!
 * \file WorkerGraph.h
 * \author aimery aviles / thomas raynal
 * \version 2.0
 */

#include <vector>
#include <iostream>
#include "AbstractTask.h"
#include "AbstractGridSlaveTask.h"
#include "Worker.h"
#include "WorkerTree.h"
#include "Utils.h"
#include <stack>
#include <math.h>

/*! \namespace Network
 * 
 * Group master/slave task template & task handling utilities (trees & graphs)
 */
namespace MasterWorkerFramework
{

/*! \class Worker
* \brief Represent a graph of slave task trees
*/
class WorkerGraph
{
public:

	WorkerGraph ()
	{
		code_=0;
	}

	~WorkerGraph()
	{

		for (std::vector<Worker*>::iterator worker = nodes.begin(); worker != nodes.end(); worker++)
			{
				if (!nodes.empty())
				{
					if (NULL!=*worker)
					{
						delete (*worker);
						worker=nodes.begin();
					}
				}
			}

	}

	/*!
	*  \brief Resolve the loaded slave task in slave task trees 
	*
	*/
	void Map__ (std::vector<AbstractGridSlaveTask*> tasks)
	{
		Map(tasks);
	}


private:
		std::vector<Worker*> nodes;
		std::vector<WorkerTree*> trees_;
		long code_;
		friend class WorkTable;		

		void FindParent (
			std::vector<AbstractGridSlaveTask*>& tasks, 
			std::vector<AbstractGridSlaveTask*>& container,
			std::vector<AbstractGridSlaveTask*>& done_elmts,
			AbstractGridSlaveTask* root
			)
		{

			AbstractGridSlaveTask* current = root;

			while (!(current==NULL))
			{
						if (!(std::find(container.begin(), container.end(),current) != container.end()))
						{
							if (!(std::find(done_elmts.begin(), done_elmts.end(),current) != done_elmts.end()))
								{
									container.push_back(current);
			   						done_elmts.push_back(current);
									FindChildren(tasks,container,done_elmts,current);
			 						FindParent(tasks,container,done_elmts,current->GetParent());
									current =current->GetParent();
								}
						}
						else
						{
							current =current->GetParent();
						}
			}
		}

		void FindChildren (
			std::vector<AbstractGridSlaveTask*>& tasks, 
			std::vector<AbstractGridSlaveTask*>& container,
			std::vector<AbstractGridSlaveTask*>& done_elmts,
			AbstractGridSlaveTask* root
			)
		{

				for (std::vector<AbstractGridSlaveTask*>::iterator vi = tasks.begin(); vi != tasks.end(); vi++)
				{
					if (!((*vi)->GetParent()==NULL))
					{
						if ((*vi)->GetParent()==root)
					 	{
							if (!(std::find(done_elmts.begin(), done_elmts.end(),*vi) != done_elmts.end()))
							{
							if (!(std::find(container.begin(), container.end(),*vi) != container.end()))
								{
										container.push_back(*vi);
			   							done_elmts.push_back(*vi);
										FindChildren(tasks,container,done_elmts,*vi);
										FindParent(tasks,container,done_elmts,(*vi));
								}
							}
						}
					}
				}

			
		}

		void Map (std::vector<AbstractGridSlaveTask*> tasks)
		{
				std::vector<std::vector<AbstractGridSlaveTask*>*> trees;
				std::vector<AbstractGridSlaveTask*> done_elts;

				for (std::vector<AbstractGridSlaveTask*>::iterator vi = tasks.begin(); vi != tasks.end(); vi++)
			      {
					  std::vector<AbstractGridSlaveTask*>* container = new std::vector<AbstractGridSlaveTask*>();
					  
					  if (!(std::find(container->begin(), container->end(),*vi) != container->end()))
						{
								if (!(std::find(done_elts.begin(), done_elts.end(),*vi) != done_elts.end()))
								{
									FindParent(tasks,*container,done_elts,*vi);
								}
						}

					  if (container->size()>0)
					  {
						  trees.push_back(container);
					  }
					  else
					  {
						  delete container;
					  }
				  }


				for (std::vector<std::vector<AbstractGridSlaveTask*>*>::iterator vi = trees.begin(); vi != trees.end(); vi++)
			      {
					  WorkerTree* worker = new WorkerTree();
					  worker->BuildTree(**vi);
					  trees_.push_back(worker);
				  }
		}



};
}
#endif